#![no_std]
#![no_main]
#![feature(lang_items)]
#![feature(default_alloc_error_handler)]

extern crate alloc;

use alloc::borrow::ToOwned;
use core::mem::size_of;
use embed_std::cstr_ptr;
use embed_std::ffi::CStr;
use embed_std::log::set_log_level;
use embed_std::{errorln, infoln};
use p2p_signal_client::ffi::{buffer_t, create_client, free_buffer_t_content, ice_info_t};
use p2p_signal_client::rapi::RSignalClient;
use p2p_signal_client::util::c_slice_as_str;
use p2p_signal_client::SignalClientOption;
use p2p_signal_client::SignalMsgId;

#[no_mangle]
pub extern "C" fn main(_argc: i32, _argv: *mut *mut i8) -> i32 {
    set_log_level(1);
    let url = "ws://localhost:20040/v1/p2p/signal".to_owned();
    let user = "test2".to_owned();
    let pwd = "123456".to_owned();
    let remote_peer_id = unsafe { CStr::from_ptr(cstr_ptr!("test@user")) };
    let opt = SignalClientOption {
        url: url.as_str(),
        user: user.as_str(),
        pwd: pwd.as_str(),
    };
    let c = unsafe { create_client(&mut opt.into()) };
    let mut client = RSignalClient::new(c);
    client.login().expect("login fail");
    let _ = client
        .create_session(&remote_peer_id)
        .expect("create session failed");
    loop_handle_msg(&mut client);
    infoln!("client ok");
    0
}

fn loop_handle_msg(client: &mut RSignalClient) -> bool {
    loop {
        if !handle_msg(client) {
            break;
        }
    }
    false
}

fn handle_msg(client: &mut RSignalClient) -> bool {
    let msg = match client.handle_msg(100) {
        Ok(Some(msg)) => msg,
        Ok(None) => {
            return false;
        }
        Err(e) => {
            errorln!("got msg error: {}", e);
            return false;
        }
    };
    let msg_id = SignalMsgId::from(msg.msg_id);
    infoln!("msg id {:?}", msg_id);
    infoln!("session id {}", msg.session_id);
    match msg_id {
        SignalMsgId::SessionCreated | SignalMsgId::SessionCreatedByRemote => {
            assert!(!msg.data.data.is_null() && msg.data.cap == size_of::<ice_info_t>() as u32);
            let ice = unsafe { &*(msg.data.data as *const ice_info_t) };
            infoln!("stun     : {}", c_slice_as_str(&ice.stun_server));
            infoln!("turn     : {}", c_slice_as_str(&ice.turn_server));
            infoln!("turn user: {}", c_slice_as_str(&ice.turn_user));
            infoln!("turn pwd : {}", c_slice_as_str(&ice.turn_pwd));
        }
        SignalMsgId::SessionClosing => {
            infoln!("session closing");
        }
        _other => {}
    }
    unsafe { free_buffer_t_content(&msg.data as *const buffer_t as *mut buffer_t) };
    true
}
